home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / audio / deliay014 / dev / src / amadeus.s next >
Text File  |  1994-10-10  |  21KB  |  654 lines

  1.  
  2.     incdir    Include40/
  3.     include    misc/AYPlayer.i
  4.     include    misc/mine.i
  5.     incdir    ''
  6.  
  7. *** Amadeus AY Player for my DT2 Play AY Emulator Interface, (C) 1994 Raxoft
  8. *** This is an example how your own AY Player could look like...
  9.  
  10. * 1 Initial version
  11. * 2 Added pushtranspose (143) a poptranspose (144) commands
  12.  
  13. ;This is how single Amadeus song looks like.
  14. ;Note that each module can contain several songs like this one...
  15. ;See aym_ structure for more info
  16.  
  17.     STRUCTURE    AMAD_Song,0
  18.     UWORD    ams_getabs    ;where the original channelA located in ZX ram
  19.     UBYTE    ams_andsix    ;strange F.F.s thing. Should be 31 normally.
  20.     UBYTE    ams_loops    ;how many loops before songend
  21.     UWORD    ams_looplen    ;len of one song loop in VBIs
  22.     WORD    ams_fadeoffset    ;precise fade specification
  23.     UWORD    ams_fadelen    ;how long to fade (not supported by DT so far)
  24.                 ;set to zero for neverending song
  25.     UBYTE    ams_assignA    ;0-3 specifies, what amiga channel will be
  26.     UBYTE    ams_assignB    ;assigned to each ay channel (A-C, noise)
  27.     UBYTE    ams_assignC
  28.     UBYTE    ams_assignN
  29.     ;original ZX data follow. First three ptrs to init channels
  30.     UWORD    ams_channelA    ;these are the original ZX data.
  31.     UWORD    ams_channelB    ;ayp_getabs says, where the ams_channelA was
  32.     UWORD    ams_channelC    ;located when it was in ZX RAM.
  33.     ;and so on...
  34.  
  35. ; The Player itself. See AYPlayer.i for more info about players in general.
  36.  
  37. dd    ;Section    AmadeusCode,code    commented because of QUICK_HACK
  38.  
  39.     AYPLAYERHEADER    AMAD
  40.     dc.b    12-1        ;custom ayfreq transpose: up octave - 1 tone
  41. AYbase    ds.l    1        ;where ay registers should be "outed"
  42. AYass    ds.l    1        ;where ay channel assignment should be copied
  43. AYfreq    ds.l    1        ;from where we can take AY frequencies
  44.     dc.w    0        ;initplayer
  45.     dc.w    0        ;endplayer
  46.     dc.w    initsound-*
  47.     dc.w    0        ;endsound
  48.     dc.w    interrupt-*
  49.     dc.w    0        ;No pattern support (patterns are pretty
  50.     dc.w    0        ;limitating and bad idea IMHO)
  51.     dc.b    'Amadeus 1.0',0
  52.     dc.b    '(C) 1987 Frantisek Fuka - Fuxoft',0
  53.     dc.b    '(C) 1992-1994 Patrik Rak - Raxoft',0
  54.     even
  55.  
  56. ;Here is the song preparation entry... PlayAY passes us ptr to our custom
  57. ;AMAD_SongStructure in a0, so it is our job to initialize our player pointers
  58. ;Also we calculate the songlen we will use later.
  59. ;Also, this is where we CAN assign AY channels to amiga channels
  60. ;(otherwise standard 0,1,2,3 assignment is made.)
  61.  
  62. initsound
  63.     lea    ams_channelA(a0),a1
  64.     moveq    #0,d0
  65.     move.w    (a0)+,d0    ;careful with the words >32767 :-)
  66.     sub.l    d0,a1
  67.     move.l    a1,getabsset    ;for ZX -> Amiga RAM relocation
  68.     move.b    (a0)+,andsix    ;FFs internal
  69.     moveq    #0,d0
  70.     move.b    (a0)+,d0    ;loops
  71.     mulu    (a0)+,d0    ;looplen
  72.     add.w    (a0)+,d0    ;add/sub offset
  73.     lea    songlen,a1
  74.     move.w    d0,(a1)+    ;store songlen
  75.     move.w    (a0)+,(a1)    ;store fadelen
  76.     move.l    AYass(pc),a1
  77.     move.l    (a0)+,(a1)    ;copy channel assignment
  78.     move.l    a0,a1        ;point to channelA
  79.     bra.b    cold        ;skip to orig. amad init routine
  80.  
  81. ;This routine is called every 1/50th of second (usually)
  82. ;Here you should process your music data and load the AY regs
  83. ;also, you can do the song len counting here - return null if song should
  84. ;continue. To signal end, return non zero value telling how many VBIs should
  85. ;DT fade.
  86.  
  87. interrupt
  88.  
  89.     bsr.w    warm    ;call orig. amadeus int. routine
  90.  
  91.     ;This is how signal songend routine should ALWAYS look like
  92.     ;Note that you MAY NOT return nonzero value more then once per song!!!
  93.     
  94.     moveq    #0,d0    ;signal continue
  95.     lea    songlen,a0
  96.     tst.w    (a0)
  97.     beq.b    .exit    ;already signalled
  98.     subq.w    #1,(a0)+    ;decrease songlen and point to fadelen
  99.     bne.b    .exit    ;not end yet
  100.     move.w    (a0),d0    ;if zero, then will never fade. Otherwise fade for x VBIs
  101. .exit    rts
  102.  
  103.  
  104. ***************************************************************************
  105.  
  106. ;Amadeus (Amiga Version for AY-3-8912 Emulator) 1.00 by Raxoft 1992
  107. ;Based on Original Amadeus V8 (C) Fuxoft 1987
  108.  
  109. ;I am not going to comment this source too detailed, because no one is going
  110. ;to read it and understand Amadeus DATA format anyway... So only roughly...
  111.  
  112. ;This code is rewrite from Z80 code, as you can see from the code design.
  113. ;I did only few optimalizations, because I didn't want to create some
  114. ;incompatibility by my mistake... So have it in mind and don't blame me...
  115.  
  116. ;Code has been sligthly rearanged by me and Delirium in 1994.
  117.  
  118. ;===========================================================================
  119.  
  120. ;Support routines for easier Z-80 emulation in 68000 code
  121.  
  122. ;GetAbs replaces this code, which is used very often in amadeus (and other
  123. ;routines as well):
  124. ;    LD    (HL),E        ;imagine that HL is a1 and DE is D7
  125. ;    INC    HL
  126. ;    LD    (HL),D
  127. ;    INC    HL
  128. ;and DE is not just some value, it is another Address Pointer to ZX data...
  129. ;This allows that there is no need to change the original data at all...
  130.  
  131. getabs    moveq    #0,d7        ;Simulates reading word address from ZX
  132.     move.b    (a1)+,d6    ;memory and recalculates it to the
  133.     move.b    (a1)+,d7    ;amiga memory. Note that ZX has LSB
  134.     lsl.w    #8,d7        ;followed MSB. And word can be on
  135.     move.b    d6,d7        ;odd address as well.
  136.     add.l    getabsset,d7    ;Returns Address in d7, also increases
  137.     rts            ;that pointer...
  138.  
  139. ;Because data in ZX memory often use direct addressing, it is necessary to
  140. ;recalculate it to your Amiga memory. Let's say you have ZX data, which were
  141. ;located on 53000, and you have them on $534a3 in your amiga memory. So you
  142. ;have to set this to $534a3-53000, otherwise the getabs won't work properly...
  143.  
  144. getabsset    dc.l    0        ;Base for your ZX memory
  145.  
  146. ;===========================================================================
  147.  
  148.  
  149. ;This code initiates all important values needed later.
  150. ;On ZX it also installed IM2 routine.
  151.  
  152. ;a1 contains pointer to first data stream
  153.  
  154. cold    lea    worksp,a6    ;Workspace
  155.  
  156.     bsr.b    getabs        ;Read three channel pointers
  157.     move.l    d7,(a6)        ;and install them to workspace
  158.     bsr.b    getabs    
  159.     move.l    d7,wrk2(a6)
  160.     bsr.b    getabs    
  161.     move.l    d7,wrk3(a6)
  162.  
  163.     move.w    #$0108,d0    ;Set note len to 1 and strobe to 8
  164.     move.w    d0,wrk1+len(a6)
  165.     move.w    d0,wrk2+len(a6)
  166.     move.w    d0,wrk3+len(a6)
  167.  
  168.     lea    stacks+stacksize-worksp(a6),a1    ;Init Channel stacks
  169.     move.l    a1,stk1-worksp(a6)
  170.     lea    stacksize(a1),a1
  171.     move.l    a1,stk2-worksp(a6)
  172.     lea    stacksize(a1),a1
  173.     move.l    a1,stk3-worksp(a6)
  174.  
  175.     clr.w    wrk1+flags(a6)    ;reset flags and transpositions
  176.     clr.w    wrk2+flags(a6)
  177.     clr.w    wrk3+flags(a6)
  178.  
  179.     clr.l    wrk1+freqbeg(a6);reset frequency envelopes stars
  180.     clr.l    wrk2+freqbeg(a6);don't think it is necessary
  181.     clr.l    wrk3+freqbeg(a6);but recoded it as well :-)
  182.  
  183.     sf    barva-worksp(a6);Clear noise color/frequency
  184.     rts
  185.  
  186. ;===========================================================================
  187.  
  188. ;This was the original routine which was called by Z80 every interrupt, pushed
  189. ;registers, called worm, poped registers, EI, RET. Now, it is the same as WARM
  190. ;indeed
  191.     
  192. ;inter    equ    warm
  193.  
  194. ;===========================================================================
  195.  
  196. ;This routine originally disabled IM2, turned on IM1 and stopped AY sound.
  197. ;Now it does only the latter, although you can also call AYoff and it will do
  198. ;the same as calling StopAMAD & AYemulate. It just puts 255 to the strobe
  199. ;register
  200.  
  201. ;No need for this routine, since the playAY will turn of the AY anyway
  202. ;(something not possible on ZX :-)
  203.  
  204. ;stopamad    lea    worksp(pc),a6
  205. ;    moveq    #-1,d0
  206. ;    bra.b    stopout
  207.  
  208. ;===========================================================================
  209.  
  210. ;Main routine, should be called every 50th of second, followed by the call
  211. ;to AYemulate.
  212.  
  213. ;Of course that you first have to install Data for amadeus, THEN call Cold, 
  214. ;and THEN you can call this.
  215.  
  216. ;It does everything: advances in all channels, generates new notes, new
  217. ;envelopes, all effects, everything...
  218.  
  219. warm    lea    worksp,a6    ;Workspace pointer to a6 as base
  220.  
  221.     lea    (a6),a5            ;Proccess Channel 1
  222.     move.l    stk1-worksp(a6),a4    ;get stack pointer
  223.     moveq    #1,d0            ;channel number
  224.     bsr.b    main            ;Oh man, DO IT !!!
  225.     move.l    a4,stk1-worksp(a6)    ;store stack pointer
  226.     
  227.     lea    wrk2(a6),a5        ;Channel 2
  228.     move.l    stk2-worksp(a6),a4
  229.     moveq    #2,d0
  230.     bsr.b    main
  231.     move.l    a4,stk2-worksp(a6)
  232.     
  233.     lea    wrk3(a6),a5        ;Channel 3
  234.     move.l    stk3-worksp(a6),a4
  235.     moveq    #3,d0
  236.     bsr.b    main
  237.     move.l    a4,stk3-worksp(a6)
  238.     
  239.     move.b    wrk3+master(a6),d0    ;Get enable bits of all
  240.     add.b    d0,d0            ;three channels and generate
  241.     or.b    wrk2+master(a6),d0    ;strobe
  242.     add.b    d0,d0
  243.     or.b    wrk1+master(a6),d0
  244.     
  245. stopout    moveq    #7,d5            ;"Out" it to the AY backup reg.
  246.     bsr.b    out            ;and fall down to outy
  247.  
  248. ;===========================================================================
  249.  
  250. ;routine which originally OUTed all register stored in memory to the AY
  251. ;at once. Now, it just copies them from AY Backup registers (note that
  252. ;everything was prepared in memory at first) to the "AY register" (in our
  253. ;case, just another part of memory:-)
  254.  
  255. ;Originally it was send there from reg 13 to reg 0, but here is no reason
  256. ;to do that so... Although in Z80 it was better solution :-)
  257.  
  258. outy    moveq    #14/2-1,d5        ;14 register to copy
  259.     lea    output-worksp(a6),a1     ;pointer to my ay output buffer
  260.     move.l    AYbase,a3        ;pointer to AY registers
  261.     
  262. outy1    move.w    (a1)+,(a3)+        ;And feed them all :-)
  263.     dbra    d5,outy1
  264.     rts
  265.  
  266. ;===========================================================================
  267.  
  268. ;Originally it was a little longer routine, which stored one byte to the
  269. ;output table. Motorola makes it in one instruction :-)
  270.  
  271. out    move.b    d0,output-worksp(a6,d5.w)
  272.     rts
  273.  
  274. ;===========================================================================
  275.  
  276. ;Main processing routine for single channel
  277.  
  278. ;a4 stack pointer for this buffer
  279.  
  280. main    move.b    d0,hlas-worksp(a6)    ;store channel number
  281.     
  282.     subq.b    #1,len(a5)    ;decrease note length, skip
  283.     beq.w    nova        ;if we need to read new one.
  284.     
  285. hl11    subq.b    #1,envper(a5)    ;dec volume envelope delay counter
  286.     bne.B    hlst        ;skip if still same volume
  287.     
  288.     move.l    envpos(a5),a1    ;Pointer to Vol Envelope stream
  289. hl1    move.b    (a1)+,d0    ;Read next volume/command
  290.     cmp.b    #128,d0        ;is it Jump?
  291.     bne.b    neskhl        ;Skip if not.
  292.     
  293.     bsr.w    getabs        ;Get the Jump destination
  294.     move.l    d7,a1        ;
  295.     bra.b    hl1        ;And continue there...
  296.     
  297. neskhl    cmp.b    #30,d0        ;0-30 used for volume 0-15
  298.     bcs.b    neskh0        ;followed by volume delay
  299.     
  300.     sub.b    #50,d0        ;values above 50 used for
  301.     move.b    d0,vol(a5)    ;volume 0-15, which has automatically
  302.     move.b    #1,envper(a5)    ;env volume delay = 1 (often used ->
  303.     bra.b    contx1        ;safes data)
  304.     
  305. neskh0    move.b    d0,vol(a5)    ;Ranges 0-30 and 50-255 are strange,
  306.     move.b    (a1)+,envper(a5);but better than try to always add
  307.                     ;128 or like by yourself... And FF
  308.                     ;wrote his musics in asm, of course...
  309. contx1    move.l    a1,envpos(a5)    ;Store the volume envelope position
  310.     
  311. hlst    move.w    freq(a5),d0    ;Skip if freq is 0 -> Generates
  312.     beq.b    playit        ;no tone
  313.     
  314.     btst    #2,flags(a5)    ;Is it first Edge? If it is, so go and
  315.     bne.b    playit        ;playit
  316.     
  317.     move.l    freqpos(a5),d0    ;Pointer to Freq envelope stream
  318.     beq.b    playit    ;!!!Just to be sure, FF is sclerotic !!!
  319.     move.l    d0,a1    ;On ZX it loads 243 from 0, but here... ?
  320.         
  321. frqc1    moveq    #0,d0        ;Get next freq/command
  322.     move.b    (a1)+,d0    
  323.     move.l    a1,freqpos(a5)    ;Store pointer to stream for next time
  324.     
  325.     cmp.b    #128,d0        ;Is it jump?
  326.     bne.b    nojpfr        ;skip if not
  327.     
  328.     bsr.w    getabs        ;Get jump destination address
  329.     move.l    d7,a1        ;as new stream
  330.     bra.b    frqc1        ;and continue there
  331.     
  332. nojpfr    cmp.b    #130,d0        ;Is it Tone Slide On command?
  333.     bne.b    nicfr1        ;Nope
  334.     
  335.     bset    #3,flags(a5)    ;Set that we will do Tone Slides
  336.     bra.b    frqc1        ;next freq/command
  337.     
  338. nicfr1    cmp.b    #131,d0        ;Is it Freq Slide On command?
  339.     bne.b    nicfr2        ;Nope
  340.     
  341.     bclr    #3,flags(a5)    ;Clear it, so we now do Freq Slides
  342.     bra.b    frqc1        ;next freq/command
  343.     
  344. nicfr2    cmp.b    #132,d0        ;Is it Tone/Noise Toggler?
  345.     bne.b    nicfr3        ;Nope
  346.     
  347.     eor.b    #9,master(a5)    ;Toggle Tone / Noise on flags
  348.     bra.b    frqc1        ;Next command
  349.  
  350. ;d0 was no command, so it is either Tone or Freq change value (depends)
  351.     
  352. nicfr3    btst    #3,flags(a5)    ;Are we in Tone Slide mode?
  353.     beq.b    nojpf0        ;Skip if in Freq Slide mode.
  354.     
  355.     add.b    tone(a5),d0    ;Add/Sub value from currently played
  356.     move.b    d0,tone(a5)    ;note and store it back
  357.  
  358. ;Note that following part can perhaps read values out of table, if not
  359. ;used carefully in music data! Also note, that value 0 is not here checked for
  360. ;silence - so it sometimes happened, that when one channel was playing only
  361. ;noise (like drum), and the transposition unforunatelly set the note to zero,
  362. ;value from (freq-2) was loaded to freq. It was OK till it was not zero (it
  363. ;was never so on ZX Amadeus), but when it happened (and of course it happened),
  364. ;value of 0 was loaded to freq here, thus disabling tone (which was disabled
  365. ;by strobe anyway), but also noise (by seting volume to zero), although it
  366. ;should play... Took me quite a while, why in several songs the drums
  367. ;sometimes sounded quite strange... That's the reason why I put
  368. ;dc.w 65535 before freqs table in FXS, just to be NOT ZERO... Now, the
  369. ;freq table goes up to 13.75 Hz, so there is a non zero value...
  370.     
  371.     add.b    d0,d0        ;Get AY frequency from the table
  372.     move.l    AYfreq(pc),a3    ;Note that first note is 1,
  373.     move.w    (a3,d0.w),freq(a5)    ;not 0 - 0 is for silence
  374.     bra.b    playit        ;and go to play sound
  375.     
  376. nojpf0    ext.w    d0        ;So it is Freq change value
  377.     
  378.     add.w    d0,d0    ;Correction - change AY freq change to
  379.     add.w    d0,d0    ;Amiga freq change...
  380.     add.w    d0,d0
  381.     
  382.     add.w    d0,freq(a5)    ;And store new frequency
  383.     
  384. ;Well, so volume and Frequency is already generated, so it is showtime
  385.  
  386. playit    move.b    barva-worksp(a6),d0    ;"Out" Noise freq
  387.  
  388.     and.b    andsix-worksp(a6),d0    ;FF sometimes use only range 0-15 ?!?!?
  389.  
  390.     moveq    #6,d5    ;(Why is it here in single channel processing?)
  391.     bsr.w    out    ;(Well, don't ask me :-)
  392.  
  393.     bclr    #2,flags(a5)    ;Set flag First Edge of Note played
  394.  
  395.     moveq    #7,d5
  396.     add.b    hlas-worksp(a6),d5 ;Get Channel number + 7 (8-10)
  397.     move.w    freq(a5),d0    ;Check frequency - if zero, then
  398.     beq.b    mlc        ;no tone AND no noise !!!
  399.     
  400.     move.b    vol(a5),d0    ;Else "Out" channel volume
  401.  
  402. mlc    bsr.w    out        ;Channel volume OR zero
  403.  
  404.     subq.b    #8,d5    ;Get channel number - 1 (0-2)
  405.     add.b    d5,d5    ;Get Freq reg position (0,2,4)
  406.     
  407.     move.b    freq(a5),d0    ;"Out" frequency
  408.     bsr.w    out
  409.     
  410.     addq.b    #1,d5
  411.     move.b    freq+1(a5),d0
  412.     bsr.w    out
  413.     
  414. navrat    rts            ;return
  415.  
  416. ;===========================================================================
  417.  
  418. ;Just store channel position as we proccess it... Originally much longer
  419. ;routine, of course :-), because of z80...
  420.  
  421. ;putpos    move.l    a1,(a5)
  422. ;    rts
  423.  
  424. ;changed to inline instruction
  425. ;and changed spec subroutines so it is not almost used... :-)
  426.  
  427. putpos    macro
  428.     move.l    a1,(a5)
  429.     endm
  430.  
  431. ;===========================================================================
  432.  
  433. ;This is called whenever new note is going to be played
  434.  
  435. nova    move.l    (a5),a1        ;Get channel position
  436. nova2    moveq    #0,d0        ;Get next note/command
  437.     move.b    (a1)+,d0
  438.     putpos        ;Remember position
  439.     
  440.     btst    #7,d0        ;Is it special command?
  441.     bne.B    spec        ;Go there if it is
  442.  
  443.     moveq    #0,d5        ;Fake freq = 0 -> will cause silence
  444.                     ;later
  445.     tst.b    d0        ;Is the note 0 (silence) ?
  446.     beq.B    notran        ;Go further if it is...
  447.     
  448.     add.b    trans(a5),d0    ;Add current Transposition to note
  449.     move.b    d0,tone(a5)    ;and store it
  450.     bclr    #3,flags(a5)    ;Turn Freq Slides on (default)
  451.     add.b    d0,d0        ;Get note frequency
  452.     move.l    AYfreq,a3
  453.     move.w    (a3,d0.w),d5
  454.     
  455. notran    move.b    (a1)+,len(a5)    ;Get number of VBIs for which it will
  456.     putpos        ;sound (0=256) and store pointer
  457.     move.w    d5,freq(a5)    ;store frequency or 0 for silence
  458.     move.l    freqbeg(a5),freqpos(a5) ;Re-Set Freq Env stream
  459.     bset    #2,flags(a5)    ;Say This is First Edge of Note
  460.                 ;to prevent early Freq Stream proccessing
  461.                 ;in case we will now jump to hl11 to
  462.                 ;keep everything synchronized
  463.                 
  464. ;Next part is little tricky. It handles continuous Volume Envelope streams,
  465. ;so eg. Volume can still fade even if we play a lot different notes.
  466. ;Bit 0 of flags says, if we want to turn this feature on, bit 1 says if
  467. ;it is already on. To turn it off, it is necessary turn both bits off.
  468. ;It is quite clever, allows control even in music nesting etc.
  469.  
  470.     btst    #1,flags(a5)    ;Already continuous Vol Envs?
  471.     bne.w    hl11        ;Proccess it if so..
  472.     
  473.     btst    #0,flags(a5)    ;Do we want turn it on?
  474.     beq.b    nic0        ;Skip if not...
  475.     
  476.     bset    #1,flags(a5)    ;From now, Vol Envs are continuous...
  477.     
  478. nic0    move.l    envbeg(a5),a3    ;Get begin of Vol Env stream
  479.     move.b    (a3)+,vol(a5)    ;and load first volume and delay
  480.     move.b    (a3)+,envper(a5);note that cannot use that +50 mode
  481.     move.l    a3,envpos(a5)    ;here. Re-Set Vol Env position.
  482.     bra.w    playit        ;And finally, play the note...
  483.  
  484. ;===========================================================================
  485.  
  486. ;This part proccesses all speciall commands found in the main channel stream,
  487. ;like gosubs, for-nexts, etc.
  488.  
  489. ;Note that we trust the data - so there is no Command Code check, and no
  490. ;Stack overflow check because of too much Gosubs or For-Nexts
  491.  
  492. spec    lea    nova2(pc),a0    ;to save some bytes
  493.     add.b    d0,d0        ;Execute proper routine...
  494.                 ;Perhaps should be slightly
  495.     lea.l    jptabl(pc,d0.w),a3 ;more CRASH PROOF :-)
  496.     add.w    (a3),a3
  497.     jmp    (a3)
  498.     
  499. jptabl    dc.w    jp-*,call-*,for_-*,next-*
  500.     dc.w    zm6-*,zmch-*,frqsta-*,def-*
  501.     dc.w    transp-*,ret_-*
  502.     dc.w    join-*,unjoin-*,usr-*
  503.     dc.w    add6-*,addtra-*
  504.     dc.w    pushtra-*,poptra-*
  505.     
  506. ;===========================================================================
  507.  
  508. jp    bsr.w    getabs        ;Stream Jump to some address
  509.     move.l    d7,a1        ;load new position.
  510.     jmp    (a0)
  511.     
  512. ;===========================================================================
  513.  
  514. call    bsr.w    getabs        ;Stream call. Remember position
  515.     move.l    a1,-(a4)
  516.     move.l    d7,a1        ;on the stack and load new one.
  517.     jmp    (a0)
  518.     
  519. ;===========================================================================
  520.  
  521. for_    move.b    (a1)+,-(a4)
  522.     subq.l    #1,a4
  523.     move.l    a1,-(a4)    ;For. Remember count and position
  524.     jmp    (a0)        ;on the steck
  525.     
  526. ;===========================================================================
  527.  
  528. next    subq.b    #1,5(a4)
  529.     beq.b    next1
  530.     move.l    (a4),a1
  531.     jmp    (a0)
  532. next1    addq.l    #6,a4
  533.     jmp    (a0)
  534.     
  535. ;===========================================================================
  536.  
  537. zm6    move.b    (a1)+,barva-worksp(a6) ;change Frequency of Noise Channel
  538.     jmp    (a0)
  539.     
  540. ;===========================================================================
  541.  
  542. zmch    move.b    (a1)+,master(a5);Select Tone AND/OR Noise On/Off
  543.     jmp    (a0)    ;Note also Toggler in Freq Env Stream, used
  544.             ;to generate pretty interesting sounds...
  545.     
  546. ;===========================================================================
  547.  
  548. def    bsr.w    getabs        ;Define Volume Envelope Stream begin
  549.     move.l    d7,envbeg(a5)    ;for following notes
  550.     jmp    (a0)
  551.     
  552. ;===========================================================================
  553.  
  554. transp    move.b    (a1)+,trans(a5)    ;Change transposition directly
  555.     jmp    (a0)
  556.     
  557. ;===========================================================================
  558.  
  559. ret_    move.l    (a4)+,a1    ;Return from subchannel. Get position from stack.
  560.     jmp    (a0)
  561.     
  562. ;===========================================================================
  563.  
  564. frqsta    bsr.w    getabs        ;Define Frequency Envelope Stream begin
  565.     move.l    d7,freqbeg(a5)    ;for following notes
  566.     jmp    (a0)
  567.     
  568. ;===========================================================================
  569.  
  570. join    bset    #0,flags(a5)    ;Turn on Continuous Volume Envelopes
  571.     bra.b    unjin
  572. ;    bclr    #1,flags(a5)
  573. ;    jmp    (a0)
  574.     
  575. ;===========================================================================
  576.  
  577. unjoin    bclr    #0,flags(a5)    ;Turn off Continuous Volume Envelopes
  578. unjin    bclr    #1,flags(a5)
  579.     jmp    (a0)
  580.     
  581. ;===========================================================================
  582.  
  583. usr    addq.l    #2,a1    ;This function was used for USER calls to any
  584.             ;Z80 code (eg. for synchronizing picture with
  585.     jmp    (a0)    ;sound as in Indiana Jones 3 by F.F.)
  586.                 ;Not implemented, OF COURSE :-)
  587.  
  588. ;===========================================================================
  589.  
  590. add6    move.b    (a1)+,d0    ;Increase/Decrease Noise Channel Freq
  591.     add.b    d0,barva-worksp(a6)    ;Used for some effects...
  592.     jmp    (a0)
  593.     
  594. ;===========================================================================
  595.  
  596. addtra    move.b    (a1)+,d0    ;Increase/Decrease Transposition level
  597.     add.b    d0,trans(a5)
  598.     jmp    (a0)
  599.     
  600. ;===========================================================================
  601.  
  602. pushtra    move.b    trans(a5),d0    ;Store Transposition level
  603.     move.w    d0,-(a4)
  604.     jmp    (a0)
  605.     
  606. ;===========================================================================
  607.  
  608. poptra    move.w    (a4)+,d0    ;Retore Transposition level
  609.     move.b    d0,trans(a5)
  610.     jmp    (a0)
  611.     
  612. ;===========================================================================
  613.  
  614.  
  615.     section    AmadeusData,bss
  616.  
  617. output    ds.b    14    ;Output space for AY registers
  618.  
  619. barva    ds.b    1    ;Noise Frequency
  620. hlas    ds.b    1    ;Temporary, for channel number
  621.  
  622. stk1    ds.l    1    ;Stack pointers for all three channels
  623. stk2    ds.l    1
  624. stk3    ds.l    1
  625.  
  626. stacksize    equ    128    ;even bigger then on ZX I think...
  627.  
  628. worksp    ds.b    3*30    ;WorkSpace for three channels, see below
  629. stacks    ds.b    3*stacksize    ;Space for Channel Stacks, used to store
  630.                 ;Gosub & For-Next informations.
  631.  
  632. wrk1    equ    0    ;Offset definitions
  633. wrk2    equ    30
  634. wrk3    equ    60
  635.  
  636. data    equ    0    ;l    ;Current Main Channel position
  637. len    equ    4    ;b    ;Delay remaining to the end of note
  638. master    equ    5    ;b    ;Partial Strobe (0,3), see AY strobe
  639. envpos    equ    6    ;l    ;Current Volume Envelope Stream Pos.
  640. envper    equ    10    ;b    ;Delay till pickup of next volume
  641. vol    equ    11    ;b    ;current volume
  642. freq    equ    12    ;w    ;current frequency
  643. envbeg    equ    14    ;l    ;Start of Volume Envelope Stream
  644. freqpos    equ    18    ;l    ;Current Freq Env Stream position.
  645. flags    equ    22    ;b    ;Flags - see code for more
  646. trans    equ    23    ;b    ;Current Transposition
  647. freqbeg    equ    24    ;l    ;Start of Freq Env Stream
  648. tone    equ    28    ;b    ;Current note
  649.  
  650. songlen    ds.w    1
  651. fadelen    ds.w    1
  652. andsix    ds.b    1
  653.  
  654.